#include "TcpServer.hpp"
#include "Protocol.hpp"
#include <memory>
#include "Calculator.hpp"

using cal_fun = std::function<Response(const Request &req)>;

class Parse
{
public:
    Parse(cal_fun gcal)
        : cal(gcal)
    {
    }
    std::string Entry(std::string &packge)
    {
        // 1判断报文的完整性
        std::string message;
        std::string respstr;
        while (Decode(packge, &message)) // 由于我们传过来的报文可能会有多个len\r\n{json}\r\n，所以需要一直用while循环来判断
        {
            LOG(LogLevel::DEBUG) << "Content: \n"
                                 << message;
            // 此时我们的message一定是成功的，因为如果解析报头出错会直接退出while循环
            if (message.empty()) // 但是我们要判断获取的message信息是否为空，为空就没必要做以下运算了
                break;

            // 2进行反序列化
            Request ret;
            if (!ret.Deserialize(message))
            {
                // 反序列化失败
                LOG(LogLevel::INFO) << "Deserialize  failed \n";
                break;
            }

            // 3计算，此时的我们的ret在反序列化的时候已经初始化完成了，可以传递这个ret用来计算
            // 虽然不知道我们的计算具体实现，但是可以肯定的是，我们要用response类获取计算结果信息
            Response res = cal(ret); // cal就是我们的回调函数的名字

            // 4序列化，此时我们的返回信息都在res中，我们需要对其进行序列化
            std::string res_str;
            res.Serialize(res_str); // res_str是一个输出型参数，此时我们就拿到了序列化后的字符串

            // 5添加报头
            Encode(res_str);

            // 6 拼接应答
            // 还记得我们在外部定义的respstr吗，这是是负责返回给服务端的字符串信息，所以我们把需要返回的信息加给他
            respstr += res_str;
        }
        LOG(LogLevel::DEBUG) << "respstr: \n"
                             << respstr;
        return respstr;
    }

private:
    // 这里需要一个计算的方法回调函数，但是我们还没实现
    cal_fun cal;
};

int main()
{
    // 1. 计算模块
    Calculator mycal;

    // 2. 解析对象
    Parse myparse([&mycal](const Request &req)
                  { return mycal.Execute(req); });

    // 3. 通信模块
    // 只负责进行IO
    std::unique_ptr<TcpServer> tcp_ptr = std::make_unique<TcpServer>([&myparse](std::string package)
                                                                     { return myparse.Entry(package); });
    tcp_ptr->InitServer();
    tcp_ptr->Start();
    return 0;
}